package initoy

import (
	"io"
	"bufio"
	"strings"
	"bytes"
)

var (
	DefaultSection = "Default"
)

type parseHelper struct {
	comment *bytes.Buffer
}

// 解析`@reader`所读取的文件至`@c`的Configuration结构体中
func parse(c *Configuration, reader io.Reader) error {
	p := parseHelper{comment: &bytes.Buffer{},}
	br := bufio.NewReader(reader)
	section, _ := c.NewSection(DefaultSection)
	for {
		line_bytes, _, err := br.ReadLine()
		if err != nil {
			if err == io.EOF {
				break
			}
			return err
		}

		line := strings.TrimSpace(string(line_bytes))
		if isEmptyLine(line) {
			continue
		}

		if isComment(line) {
			p.comment.Write(append([]byte(line), '\n'))
			continue
		}

		if isSection(line) {
			sec_name, close_idx, err := parseSection(line)
			if err != nil {
				return err
			}
			section, err = c.NewSection(sec_name)
			if err != nil {
				return err
			}

			following := strings.TrimSpace(line[close_idx+1:])
			if isComment(following){
				p.comment.Write([]byte(following))
			}
			section.comment = strings.TrimSpace(p.comment.String())
			p.comment.Reset()
			continue
		}

		if isKey(line) {	
			key_name, value, close_idx, err := parseKey(line)
			if err != nil {
				return err
			}
			key, err := section.NewKey(key_name, value)
			if err != nil {
				return err
			}

			following := strings.TrimSpace(line[close_idx+1:])
			if isComment(following){
				p.comment.Write([]byte(following))
			}
			key.comment = strings.TrimSpace(p.comment.String())
			p.comment.Reset()
		}
	}
	return nil
}

// 判断`@line`是否为空行
func isEmptyLine(line string) bool {
	return line == ""
}

// 判断`@line`是否为注释
func isComment(line string) bool {
	if len(line) <= 0{
		return false
	}
	return line[0] == byte(CommentHeader)
}

// 判断`@line`是否为Section
func isSection(line string) bool {
	if len(line) <= 0{
		return false
	}
	return line[0] == '['
}

// 判断`@line`是否为键值对
func isKey(line string) bool {
	index := strings.Index(line, "=")
	if index < 0 {
		return false
	}
	return true
}

// 解析`@line`所记的Section名称，并返回']'所在的下标
func parseSection(line string) (string, int, error) {
	close_idx := bytes.LastIndexByte([]byte(line), ']')
	if close_idx == -1 {
		return "", close_idx, &unclosedSectionError{line:line,}
	}
	name := line[1:close_idx]
	return name, close_idx, nil
}

// 解析`@line`所记的键值对键名和值，并返回随后注释'#'所在的下标（如果有的话）
func parseKey(line string) (string, string, int,error) {
	index := strings.Index(line, "=")
	key := strings.TrimSpace(line[:index])
	if len(key) <= 0 {
		return "", "", -1, &keyUndefinedError{line:line,}
	}
	close_idx := strings.Index(line, string(CommentHeader))
	var value string
	if close_idx == -1{
		value = strings.TrimSpace(line[index+1:])
	} else {
		value = strings.TrimSpace(line[index+1: close_idx])
	}
	if len(value) <= 0 {
		return "", "", -1, &valueUndefinedError{line:line,}
	}
	return key, value, close_idx, nil
}